home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / byte0387.arc / DAWSON.ARC / SIMAREA.C < prev    next >
Encoding:
C/C++ Source or Header  |  1985-07-12  |  7.8 KB  |  267 lines

  1.  
  2. /*******************************************\
  3. *                         *
  4. *   simarea.c = Area operations for SIMPP:  *
  5. *   Simple IMage Processing Package.        *
  6. *   Copyright (c) 1987, Benjamin M. Dawson  *
  7. *      Edit Version: 1.1 : Jan-29-87        *
  8. *                         *
  9. \*******************************************/
  10.  
  11. #include "simpp.h"
  12.  
  13. extern char *malloc();
  14.  
  15. /* convolve = Convolve the image area starting at x,y and of size dx,dy
  16.  * with the kernel of size m,n.  Scale (divide) the output by scale, and
  17.  * change the sign of the output values according to the output flag.
  18.  */
  19. int convolve(x,y,dx,dy,m,n,kernel,scale,output)
  20. int x,y;        /* Start of area to convolve */
  21. int dx,dy;        /* Size of area to convolve */
  22. int m,n;        /* Kernel (x,y) size */
  23. int *kernel;        /* Pointer to kernel array */
  24. int scale;        /* Amount to right shift results */
  25. int output;        /* Output flag */
  26. {
  27.     PIXEL *bp[MAX_KERNEL_SIZE];        /* Input pointers */
  28.     PIXEL *ptemp;                /* Temporary pointer */
  29.     register int i,j;            /* Loop variables */
  30.     int x_out,y_out;            /* output x,y index */
  31.     int xx;                    /* Offset x address */
  32.     int xend;                /* Reduced x size */
  33.     long sum;                /* Convolution sum */
  34.     long max_pos;                /* Maximum + pixel value */
  35.     long maxs_pos;                /* Maximum signed + value */
  36.     long maxs_neg;                /* Maximum signed - value */
  37.     int *kp;                /* Pointer to kernel */
  38.  
  39. #ifdef CHECK
  40. /* Check source and destination ranges */
  41.     if (check_area(x,y,dx,dy,"<convolve>") == ERROR)
  42.          return(ERROR);
  43. /* Check kernel size */
  44.     if ((m > MAX_KERNEL_SIZE) || (m < 1) ||
  45.         (n > MAX_KERNEL_SIZE) || (n < 1)) {
  46.         printf("<convolution> Kernel size out of range!\n");
  47.         return(ERROR);
  48.         }
  49. /* Special check against kernel size */
  50.     if ((dx < m) || (dy < n)) {
  51.         printf("<convolution> Area too small!\n");
  52.         return(ERROR);
  53.     }
  54. #endif
  55.  
  56. /* Set up long values for output value checking */
  57.     max_pos = (long)MAXPIX;
  58.     maxs_pos = max_pos/2L;
  59.     maxs_neg = -((long)(PIXEL_SIZE/2));
  60.  
  61. /* Allocate line buffers for input */
  62.     for (i = 0 ; i < n ; i++)
  63.         bp[i] = (PIXEL *)malloc(dx*sizeof(PIXEL));
  64.  
  65. /* Set up addresses and indices */
  66.     x_out = x + (m/2);    /* These factors correct for the convolution */
  67.     y_out = y + (n/2);    /*   edge effects (see BYTE article) */
  68.     dy -= (n-1);        /* Reduce area to account for edge effects */
  69.     xend = dx - m;
  70.  
  71. /* Read first n lines into the input buffers */
  72.     for (i = 0 ; i < n ; i++) read_hline(x,y++,dx,bp[i]);
  73.  
  74. /* Main convolution loop */
  75.     while (dy--) {            /* Scan down the image */
  76.       for (xx = 0 ; xx <= xend ; xx++) {    /* Scan across the image */
  77. /* Inner loop */
  78.         sum = 0L;        /* 0 out convolution sum */
  79.         kp = kernel;        /* Set up pointer to kernel */
  80.         for (j = 0 ; j < n ; j++) {
  81.           ptemp = bp[j] + xx;    /* Point to line area with pixels */
  82.           for (i = 0 ; i < m ; i++ )
  83.             sum += ((long)*ptemp++)*((long)*kp++);
  84.         }
  85. /* Scale the output sum quickly with a shift right operation.  Unfortunately,
  86.    a shift right some machines fills 0's rather than the sign bit.  A ifdef
  87.    selects for these unfortunate machines */
  88. #ifdef NO_SIGN_FILL
  89.         if (sum < 0) {
  90.             sum = -sum;
  91.             sum >>= (long)scale;
  92.             sum = -sum;
  93.         }
  94.         else sum >>= (long)scale;
  95. # else
  96.         sum >>= (long)scale;
  97. #endif
  98.  
  99. /* Output value modified according to output flag */
  100.       switch(output) {
  101.         case SIGNED:        /* Clip values to range from */
  102.           if (sum < maxs_neg) sum = maxs_neg;    /* maxs_neg to */
  103.           if (sum > maxs_pos) sum = maxs_pos;    /* maxs_pos */
  104.           break;
  105.         case POSITIVE:        /* Positive values only. - set to 0 */
  106.           if (sum < 0L) sum = 0L;
  107.           if (sum > max_pos) sum = max_pos;
  108.           break;
  109.         case NEGATIVE:        /* Negative only. Sign inverted. */
  110.           if (sum > 0L) sum = 0L;
  111.           sum = - sum;
  112.           if (sum > max_pos) sum = max_pos;
  113.           break;
  114.         case ABSOLUTE:        /* Absolute value */
  115.           if (sum < 0L) sum = -sum;
  116.           if (sum > max_pos) sum = max_pos;
  117.           break;
  118.           }
  119.  
  120.       write_pixel(x_out+xx,y_out,(PIXEL)sum);    /* Write out value */
  121.       }
  122. /* Shuffle pointers so that all is in order */
  123.     ptemp = bp[0];
  124.     for (i = 0 ; i < n-1 ; i++)    /* Shift buffer pointers */
  125.         bp[i] = bp[i+1];
  126.     bp[n-1] = ptemp;
  127. /* Replace oldest line with new line, and move down a line */
  128.     read_hline(x,y++,dx,bp[n-1]);
  129.     y_out++;
  130.     }
  131.  
  132. /* Free buffers */
  133.     for (i = 0 ; i < n ; i++) free(bp[i]);
  134.     return(OK);
  135. }
  136.  
  137. /* ================================================================ */
  138.  
  139. /* label = Label an area.  The pixels in the area must be binary with target
  140.  * value == bin1 and background value of bin0.  The area is scanned for
  141.  * connected groups of pixels (blobs).  If a connected area has more
  142.  * than minpix pixels, it's values are changed to a label.  Labels
  143.  * are chosen sequentially starting at blabel and going to elabel, then
  144.  * the label values repeat.  The binary values, bin0 and bin1, must NOT
  145.  * be part of the label set!!!  Areas less than minpix are "killed" by
  146.  * setting them to bin0.  This improves processing speed.
  147.  */
  148.  
  149. /* Static variables to save stack space */
  150. static int count = 0;            /* Count of pixels in area */
  151. static PIXEL oldcolor = 0;        /* Target color */
  152. static PIXEL newcolor = 0;        /* Label color */
  153. static int xleft = 0;            /* Boundary values */
  154. static int ytop = 0;            /* For checking recursion area */
  155. static int xright = XSIZE-1;
  156. static int ybottom = YSIZE-1;
  157.  
  158. int label(x,y,dx,dy,bin0,bin1,minpix,blabel,elabel)
  159. int x,y;        /* Start of area to label */
  160. int dx,dy;        /* Size of area to label */
  161. PIXEL bin0;        /* Binary 0 value */
  162. PIXEL bin1;        /* Binary 1 value */
  163. int minpix;        /* Minimum number of connected pixels for label */
  164. PIXEL blabel;        /* Begining value to label with */
  165. PIXEL elabel;        /* End value to label with */
  166. {
  167.     register int i;
  168.     PIXEL lv;
  169.  
  170. #ifdef CHECK
  171. /* Check area to scan */
  172.     if (check_area(x,y,dx,dy,"<label>") == ERROR)
  173.         return(ERROR);
  174. /* Check that the specified labels are not the same as binary values */
  175.     if ((blabel == bin0) || (blabel == bin1) ||
  176.         (elabel == bin0) || (elabel == bin1)) {
  177.         printf("<label> Labels cannot == binary values!!\n");
  178.         return(ERROR);
  179.     }
  180. #endif
  181.  
  182. /* Set up boundary values */
  183.     xleft = x;
  184.     ytop = y;
  185.     xright = x+dx-1;
  186.     ybottom = y+dy-1;
  187. /* Set up label value */
  188.     lv = blabel;
  189. /* Search area */
  190.     while (dy--) {
  191.         for (i = x ; i < dx+x ; i++) {
  192. /* If there is a target pixel, fill it */
  193.             if (read_pixel(i,y) == bin1) {
  194.                 count = 0;    /* Count of pixels */
  195.                 oldcolor = bin1;/* Target color */
  196.                 newcolor = lv;    /* Color to fill with */
  197.                 fill_horiz(i,y);    /* Fill with value */
  198.                 if (count < minpix) {  /* Erase if < minpix */
  199.                     oldcolor = lv;
  200.                     newcolor = bin0;
  201.                     fill_horiz(i,y);
  202.                 }
  203.                 else {             /* Bump color */
  204.                     if (++lv > elabel) lv = blabel;
  205.                 }
  206.             }
  207.         }
  208.         y++;
  209.     }
  210.  
  211.     return(OK);
  212. }
  213.  
  214. /* ================================================================ */
  215.  
  216. /* Recursion/iteration routines for finding and filling connected areas */
  217.  
  218. static int xl,xr;
  219.  
  220. /* Horizontal fill recursion.  Does most of the work... */
  221. static VOID fill_horiz(x,y)
  222. int x,y;
  223. {
  224. /* Is this a hit? */
  225.     if (read_pixel(x,y) == oldcolor) {
  226. /* Change as long a horizontal line as you can.  Keep track of x, dx */
  227.         xr = x;
  228.         while (xr <= xright) {
  229.             if (read_pixel(xr,y) == oldcolor) {
  230.                 write_pixel(xr++,y,newcolor);
  231.                 count++;
  232.             }
  233.             else break;
  234.         }
  235.  
  236.         xl = x-1;
  237.         while (xl >= xleft) {
  238.             if (read_pixel(xl,y) == oldcolor) {
  239.                 write_pixel(xl--,y,newcolor);
  240.                 count++;
  241.             }
  242.             else break;
  243.         }
  244.     xl++;
  245.     if ((xr-xl) > 0) fill_vert(xl,y,xr-xl);
  246.     }
  247. }
  248.  
  249. /* vertical fill recursion */
  250. static VOID fill_vert(x,y,dx)
  251. int x,y,dx;
  252. {
  253.     while(dx--) {
  254. /* Boundary check and recurse up */
  255.         if (--y >= ytop) fill_horiz(x,y);
  256.         y++;
  257. /* Boundary check and recurse down (Remember: "Video coordinates") */
  258.         if (++y <= ybottom) fill_horiz(x,y);
  259.         y--;
  260.         x++;
  261.     }
  262. }
  263.  
  264. /* ================ End of simarea.c ================ */
  265.  
  266. /* <-- FILE BREAK --> */
  267.